/*
 * lineplot.cpp
 *
 *  Created on: 22.3.2010
 *      Author: aahv
 */

#include "lineplot.h"
#include "utils.h"

#include <QPainter>

LinePlot::LinePlot(QWidget* parent) : QWidget(parent), data(NULL)
{
    yAxisTickCount = 5;
    zeroVisible = true;
    gridVisible = true;

    xAxisMajorTickFreq = 1;

    font = QFont();
#ifdef Q_OS_SYMBIAN
    if(Utils::smallScreen()) {
        font.setPointSize(2);
    } else {
        font.setPointSize(4);
    }

#else
    font.setPointSize(10);
#endif
}

void LinePlot::setData(LinePlotData *data)
{
    this->data = data;

    QFontMetrics metrics = QFontMetrics(font);
    xAxisLabelMetrics = metrics.boundingRect(data->getData(0).toString());
    yAxisLabelMetrics = metrics.boundingRect(QString::number(data->getMaxValue()));
}

void LinePlot::setXAxisMajorTickFrequency(int freq)
{
    xAxisMajorTickFreq = freq;
}

void LinePlot::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);

    calculateGeometry();
}

void LinePlot::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    if (data == 0)
        return;

    calculateGeometry();

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::TextAntialiasing, true);       

    painter.setFont(font);

    drawAxis(painter);
    drawData(painter);
}

void LinePlot::drawAxis(QPainter &painter) const
{

    QPen pen = QPen(QColor(0, 0, 0, 255));
    pen.setWidth(3);
    pen.setCapStyle(Qt::RoundCap);
    painter.setPen(pen);
    painter.drawLine(origo, xAxisEnd);
    painter.drawLine(origo, yAxisEnd);

    QPen gridPen = QPen(QColor(191, 191, 191, 255));
    
    for (int i = 0; i < yAxisTickCount; ++i) {
        int const y = yCoordinateForTick(i);
        QPoint p1 = QPoint(origo.x() - 6, y);
        QPoint p2 = QPoint(origo.x(), y);
        painter.setPen(pen);
        painter.drawLine(p1, p2);

        // Added 1 to width and height because on smaller screens few pixels were clipped from the y axis tick label
        QRect rect = QRect(origo.x() - yAxisLabelMetrics.width() - 10,
                           y - yAxisLabelMetrics.height() / 2,
                           yAxisLabelMetrics.width() + 1,
                           yAxisLabelMetrics.height() + 1);
        painter.drawText(rect, QString::number(yValueForTick(i)), QTextOption(Qt::AlignRight));

        if (gridVisible) {
            painter.setPen(gridPen);
            painter.drawLine(p1, QPoint(xAxisEnd.x(), y));
        }
    }

    int const xAxisTickCount = data->getDataCount();
    for (int i = 0; i < xAxisTickCount; ++i) {
        int x = xCoordinateForTick(i);
        QPoint p1 = QPoint(x, origo.y());
        QPoint p2 = QPoint(x, origo.y() + (i % xAxisMajorTickFreq == 0? 6: 3));
        painter.setPen(pen);
        painter.drawLine(p1, p2);

        if (i % xAxisMajorTickFreq == 0) {
            QString tickLabel = data->getData(i).toString();

            painter.save();
            painter.translate(x - xAxisLabelMetrics.width() / 2, origo.y() + xAxisLabelMetrics.width() + 6);
            painter.rotate(-45);
            painter.drawText(0, 0, tickLabel);
            painter.restore();
        }

        if (gridVisible) {
            painter.setPen(gridPen);
            painter.drawLine(p1, QPoint(x, yAxisEnd.y()));
        }
    }
}

void LinePlot::drawData(QPainter &painter) const
{
    QPen linePen = QPen(QColor(21, 88, 138, 255));
    if(Utils::smallScreen()) {
        linePen.setWidth(1);
    } else {
        linePen.setWidth(3);
    }
    painter.setPen(linePen);

    QPoint p1;
    int const xAxisTickCount = data->getDataCount();
    for (int i = 0; i < xAxisTickCount; ++i) {
        int const x = xCoordinateForTick(i);
        int const y = yCoordinateForValue(i);

        if (i > 0) {    
            painter.drawLine(p1, QPoint(x, y));
        }

        p1 = QPoint(x, y);

        painter.drawEllipse(p1, 3, 3);
    }
}

void LinePlot::calculateGeometry()
{
    QRect area = rect();

    origo = QPoint(area.left() + yAxisLabelMetrics.width() + 15, area.bottom() - xAxisLabelMetrics.width() - 10);

    xAxisEnd = QPoint(area.right() - 5, origo.y());
    yAxisEnd = QPoint(origo.x(), area.top() + 5);

    yAxisTickCount = area.height() / 40;
    if (data && yAxisTickCount > data->getMaxValue())
        yAxisTickCount = data->getMaxValue();
}

int LinePlot::xCoordinateForTick(int index) const
{
    int const xAxisTickCount = data->getDataCount();
    int const xAxisLength = xAxisEnd.x() - origo.x();
    int const xOffset = (xAxisTickCount <= 1) ? 0 :
              (index * (xAxisLength - 10) / (xAxisTickCount - 1));
    return origo.x() + 5 + xOffset;
}

int LinePlot::yCoordinateForTick(int index) const
{
    int const yAxisLength = origo.y() - yAxisEnd.y();
    int const yOffset = (yAxisTickCount <= 1) ? 5 :
              (index * yAxisLength / (yAxisTickCount - 1));
    return origo.y() - yOffset; 
}

int LinePlot::yCoordinateForValue(int index) const
{
    int const yAxisLength = origo.y() - yAxisEnd.y();
    int const yOffset = (yAxisTickCount <= 1) ? 5 :
        (data->getValue(index) - yAxisMinValue()) * yAxisLength / yAxisValueDiff();
    return origo.y() - yOffset; 
}

int LinePlot::yValueForTick(int index) const
{
    if(yAxisTickCount <= 1)
        return yAxisMinValue();
    
    return yAxisMinValue() + (index * yAxisValueDiff() / (yAxisTickCount - 1));
}
